package application;





import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.media.AudioClip;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;


public class DisplayMap {
	
	
	AudioClip mouseEnterAudio;
	AudioClip mouseClickAudio;
	
	 double scale;
	 int designMap[][];
	 ImageView[][] imageViews;
	 int numberOfRows;
	 int numberOfColumns;
	 
	 Pane mapPane = new Pane();
	 
	 SimpleDoubleProperty blockSize;
	 double maxBlockSize;
	 
	 boolean isChange;
	 
	 int originLocation[];
	 int rotateAngle;
	
	 
	 public DisplayMap() {
		 mouseEnterAudio = new AudioClip(new File("auds/MouseEnter.mp3").toURI().toString());
		 mouseClickAudio = new AudioClip(new File("auds/MouseClick.mp3").toURI().toString());
		 scale = BasicTools.scale.getValue();
		 isChange = false;
		 blockSize = new SimpleDoubleProperty();
	 }
	 
	 
	 
	public  Scene getDisplayMapScene(Stage primaryStage, String levelName, String gameMode) throws FileNotFoundException{
		mouseEnterAudio.volumeProperty().bind(BasicTools.volumeValue);
		mouseClickAudio.volumeProperty().bind(BasicTools.volumeValue);
		getNumbers(levelName, gameMode);
		maxBlockSize = Math.min( BasicTools.windowSize[0] / (numberOfColumns + 2), (BasicTools.windowSize[1] - (30 + 10 + 13 * 4  * scale )) / (numberOfRows + 2));
		blockSize.setValue(maxBlockSize);
		
		BorderPane borderPane = new BorderPane();
		borderPane.setStyle("-fx-background-image: url(file:pics/GameBackground.png); -fx-background-size: " + 
				BasicTools.windowSize[0] + " " + BasicTools.windowSize[1]);
		borderPane.setCenter(mapPane);

		drawBlocks(levelName, gameMode);
		
		Scene scene = new Scene(borderPane);
		
		borderPane.setTop(getControlPane(primaryStage, scene, levelName));
		
		Hero hero = new Hero(gameMode, levelName, originLocation, rotateAngle);
		
		
		primaryStage.widthProperty().addListener(e -> {
			
			double maxBlockSize = Math.min( BasicTools.windowSize[0] / (numberOfColumns + 2), (BasicTools.windowSize[1] - 100) / (numberOfRows + 2));
			
			if (maxBlockSize < this.maxBlockSize) {
				isChange = true;
				blockSize.setValue(maxBlockSize);
			}
			
			scale = BasicTools.scale.getValue();
			
			borderPane.setTop(getControlPane(primaryStage, scene, levelName));
			
			this.maxBlockSize = maxBlockSize;
			
			borderPane.setStyle("-fx-background-image: url(file:pics/GameBackground.png); -fx-background-size: " + 
					BasicTools.windowSize[0] + " " + BasicTools.windowSize[1]);
		});
		
		
		blockSize.addListener(e -> {
			try {	
				if (isChange) {
					mapPane.getChildren().clear();
					drawBlocks(levelName, gameMode);
					hero.setHeroImageView();
					hero.displayHero();
					isChange = false;
				}
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		});
		
		
		ActionHandler actionHandler = new ActionHandler(hero, scene);		
		scene.setOnKeyPressed(actionHandler);
		return scene;
	}

	public  void getNumbers(String levelName, String gameMode) throws FileNotFoundException{
		
		numberOfRows = 0;
		numberOfColumns = 0;
		
		String levelLocation;
		if (gameMode == "GameModeOne")
			levelLocation = "gamelevels/adventure_mode_levels/" + levelName + ".txt";
		else 
			levelLocation = "gamelevels/free_mode_levels/" + levelName + ".txt";
		
		File file = new File(levelLocation);
		
		Scanner scanner = new Scanner(file);
		String firstLineString = scanner.nextLine();
		numberOfRows++;
		while (scanner.hasNext()) {
			numberOfRows++;
			scanner.nextLine();
		}
		scanner.close();
		Scanner lineScanner = new Scanner(firstLineString);
		while (lineScanner.hasNext()) {
			numberOfColumns++;
			lineScanner.next();
		}
		lineScanner.close();
		
		designMap = new int[numberOfRows + 2][numberOfColumns + 2];
		imageViews = new ImageView[numberOfRows + 2][numberOfColumns + 2];
	}
	
	
	public  void drawBlocks(String levelName, String gameMode) throws FileNotFoundException {
		
		String levelLocation;
		if (gameMode == "GameModeOne")
			levelLocation = "gamelevels/adventure_mode_levels/" + levelName + ".txt";
		else 
			levelLocation = "gamelevels/free_mode_levels/" + levelName + ".txt";
		
		File file = new File(levelLocation);
		Scanner scanner = new Scanner(file);
		
		Image blankImage = new Image("/pics/blank.png");
		Image blockImage = new Image("/pics/block.png");
		Image DestinationImage = new Image("/pics/Destination.png");
		
	
		DoubleBinding xSpace = mapPane.widthProperty().subtract((numberOfColumns + 2) * blockSize.getValue()).divide(2);
		DoubleBinding ySpace = mapPane.heightProperty().subtract((numberOfRows + 2) * blockSize.getValue()).divide(2);
	
		
		
		
		
		for (int i = 0; i < designMap.length; i++) {
			for (int j = 0; j < designMap[i].length; j++) {
				if(i != 0 && i != designMap.length - 1 && j != 0 && j !=designMap[i].length - 1 ) {
					designMap[i][j] = Integer.parseInt(scanner.next());
				}
				else {
					designMap[i][j] = -1;
				}
				if (designMap[i][j] == -1) {
					imageViews[i][j] = new ImageView(blockImage);
					imageViews[i][j].setFitWidth(blockSize.getValue());
					imageViews[i][j].setFitHeight(blockSize.getValue());
					imageViews[i][j].xProperty().bind(xSpace.add(blockSize.getValue() * j));
					imageViews[i][j].yProperty().bind(ySpace.add(blockSize.getValue() * i));
					mapPane.getChildren().add(imageViews[i][j]);
				}
				else if(designMap[i][j] == 0) {
					imageViews[i][j] = new ImageView(blankImage);
					imageViews[i][j].setFitWidth(blockSize.getValue());
					imageViews[i][j].setFitHeight(blockSize.getValue());
					imageViews[i][j].xProperty().bind(xSpace.add(blockSize.getValue() * j));
					imageViews[i][j].yProperty().bind(ySpace.add(blockSize.getValue() * i));
					mapPane.getChildren().add(imageViews[i][j]);
				}
				else if(designMap[i][j] == -99) {
					imageViews[i][j] = new ImageView(DestinationImage);
					imageViews[i][j].setFitWidth(blockSize.getValue());
					imageViews[i][j].setFitHeight(blockSize.getValue());
					imageViews[i][j].xProperty().bind(xSpace.add(blockSize.getValue() * j));
					imageViews[i][j].yProperty().bind(ySpace.add(blockSize.getValue() * i));
					mapPane.getChildren().add(imageViews[i][j]);
				}
				else if(designMap[i][j] > 0 && designMap[i][j] < 5) {
					imageViews[i][j] = new ImageView(blankImage);
					imageViews[i][j].setFitWidth(blockSize.getValue());
					imageViews[i][j].setFitHeight(blockSize.getValue());
					imageViews[i][j].xProperty().bind(xSpace.add(blockSize.getValue() * j));
					imageViews[i][j].yProperty().bind(ySpace.add(blockSize.getValue() * i));
					mapPane.getChildren().add(imageViews[i][j]);
					originLocation = new int[2];
					originLocation[0] = i;
					originLocation[1] = j;
					rotateAngle = designMap[i][j] - 1;
				}
				
			}
		}
		scanner.close();
	}
	
	
	public  Pane getControlPane(Stage primaryStage, Scene backScene, String levelNanme) {	
		
		HBox controlPane = new HBox(30 * scale);
		controlPane.setPadding(new Insets(10 * scale, 10 * scale, 10 * scale, 10 * scale));

		controlPane.getChildren().addAll(getBackLabel(primaryStage), getSettingsLabel(primaryStage, backScene));
		controlPane.getChildren().add(getLevelNamePane(levelNanme));
		return controlPane;
	}
	
	
	public Label getBackLabel(Stage primaryStage) {
		
		ImageView imageView1 = new ImageView("pics/BackLabel1.png");
		ImageView imageView2 = new ImageView("pics/BackLabel2.png");
		
		imageView1.setFitWidth(37 * 4  * scale);
		imageView1.setFitHeight(13 * 4  * scale);
		imageView2.setFitWidth(37 * 4  * scale);
		imageView2.setFitHeight(13 * 4 * scale);
		
		Label backLabel = new Label("", imageView1);
	
		backLabel.setOnMouseClicked(e -> {
			mouseClickAudio.play();
			BasicTools.changeSceneExpand(primaryStage, new LevelSelect().getLevleSelectScene(primaryStage));
		});
		
		backLabel.setOnMouseEntered(e ->{
			mouseEnterAudio.play();
			backLabel.setGraphic(imageView2);
		});
		
		backLabel.setOnMouseExited(e -> {
			backLabel.setGraphic(imageView1);
		});
		
		return backLabel;
	}
	
	
	public Label getSettingsLabel(Stage primaryStage, Scene backScene) {
		
		
		ImageView imageView1 = new ImageView("pics/SettingsLabel1.png");
		ImageView imageView2 = new ImageView("pics/SettingsLabel2.png");
		
		imageView1.setFitWidth(37 * 4  * scale);
		imageView1.setFitHeight(13 * 4  * scale);
		imageView2.setFitWidth(37 * 4  * scale);
		imageView2.setFitHeight(13 * 4 * scale);

		Label settingsLabel = new Label("", imageView1);
		settingsLabel.setOnMouseClicked(e -> {
			mouseClickAudio.play();
			BasicTools.changeSceneExpand(primaryStage, new Settings().getSettingsScene(primaryStage, backScene));
			isChange = false;
		});
		
		settingsLabel.setOnMouseEntered(e ->{
			mouseEnterAudio.play();
			settingsLabel.setGraphic(imageView2);
		});
		
		settingsLabel.setOnMouseExited(e -> {
			settingsLabel.setGraphic(imageView1);
		});
		
		
		return settingsLabel;
	}
	
	
	public HBox getLevelNamePane(String levelName) {		
		Label label = new Label(levelName);
		label.setTextFill(Color.WHITE);
		label.setFont(Font.font("Times New Roman", FontWeight.BOLD, FontPosture.ITALIC, 20 * scale));
		HBox hBox = new HBox();
		hBox.setPadding(new Insets(10 * scale, 0, 0, 165 * scale));
		hBox.getChildren().add(label);
	
		return hBox;
	}
	
	public  class Hero{
		
		ArrayList<Integer> location = new ArrayList<>();
		
		Double imageViewSize;
		Image[] dogImages = {new Image("/pics/Dog_Down.png"), new Image("/pics/Dog_Left.png"), new Image("/pics/Dog_Up.png"), new Image("/pics/Dog_Right.png") };
		ImageView heroImageView =  new ImageView();
		String gameMode;
		String levelName;
		int rotateAngle;
		AudioClip walkOnGrassAudioClip = new AudioClip(new File("auds/WalkOnGrass.mp3").toURI().toString());
		AudioClip getBoneAudioClip = new AudioClip(new File("auds/GetBone.mp3").toURI().toString());
		AudioClip hitAudio = new AudioClip(new File("auds/Hit.mp3").toURI().toString());
		
		
		
		DoubleBinding xSpace = mapPane.widthProperty().subtract((numberOfColumns + 2) * blockSize.getValue()).divide(2);
		DoubleBinding ySpace = mapPane.heightProperty().subtract((numberOfRows + 2) * blockSize.getValue()).divide(2);

		
		public Hero(String gamemode, String levelName, int[] originLocation, int rotateAngle) {
			this.gameMode = gamemode;
			this.levelName = levelName;
			this.location.add(originLocation[0]);
			this.location.add(originLocation[1]);
			
			walkOnGrassAudioClip.volumeProperty().bind(BasicTools.volumeValue);
			getBoneAudioClip.volumeProperty().bind(BasicTools.volumeValue);
			hitAudio.volumeProperty().bind(BasicTools.volumeValue);
			heroImageView.setImage(dogImages[rotateAngle]);
			setHeroImageView();
			displayHero();
		}
		
		public void setHeroImageView() {
			imageViewSize = blockSize.getValue();
			heroImageView.setFitWidth(imageViewSize);
			heroImageView.setFitHeight(imageViewSize);
			heroImageView.setRotate(0);
			xSpace = mapPane.widthProperty().subtract((numberOfColumns + 2) * blockSize.getValue()).divide(2);
			ySpace = mapPane.heightProperty().subtract((numberOfRows + 2) * blockSize.getValue()).divide(2);
			setLocation(location.get(0), location.get(1));
		}
		

		
		public void setLocation(int x, int y) {
			location.set(0, x);
			location.set(1, y);
			heroImageView.xProperty().bind(xSpace.add(blockSize.getValue() / 2 - imageViewSize / 2 + blockSize.getValue() * location.get(1)));
			heroImageView.yProperty().bind(ySpace.add(blockSize.getValue() / 2 - imageViewSize / 2 + blockSize.getValue() * location.get(0)));
			heroImageView.setRotate(rotateAngle);
		}
		
		public void setRotate(int rotateAngle) {
			this.rotateAngle = rotateAngle;
			heroImageView.setImage(dogImages[rotateAngle]);;
		}
		
		public void displayHero() {
			mapPane.getChildren().add(heroImageView);
			heroImageView.xProperty().bind(xSpace.add(blockSize.getValue() / 2 - imageViewSize / 2 + blockSize.getValue() * location.get(1)));
			heroImageView.yProperty().bind(ySpace.add(blockSize.getValue() / 2 - imageViewSize / 2 + blockSize.getValue() * location.get(0)));
		}
		
		public void judgeOut(Scene scene) {
			if (designMap[location.get(0)][location.get(1)] == -99) {
				ImageView victoryImageView = new ImageView("/pics/Yummy.png");
				victoryImageView.setFitHeight(64 * 6 * scale);
				victoryImageView.setFitWidth(73 * 6 * scale);
				victoryImageView.setX(mapPane.getWidth() / 2 - victoryImageView.getFitWidth()/ 2);
				victoryImageView.setY(mapPane.getHeight() / 2 - victoryImageView.getFitHeight() / 2 - 20);
				getBoneAudioClip.play();
				mapPane.getChildren().add(victoryImageView);
			
				heroImageView.setImage(null);
		
				imageViews[location.get(0)][location.get(1)].setImage(new Image("/pics/blank.png"));
				imageViews[location.get(0)][location.get(1)].setFitWidth(blockSize.getValue());
				imageViews[location.get(0)][location.get(1)].setFitHeight(blockSize.getValue());
				scene.setOnKeyPressed(null);
		
				
				if (gameMode == "GameModeOne") {
					unlockNextLevel(levelName);
				}
			}
		}
	}
	
	
	public void unlockNextLevel(String levelName) {
		ArrayList<String> modeOneLevels = new ArrayList<>();
		ArrayList<Integer> modeOneLevelsState = new ArrayList<>();
		
		try (Scanner scanner = new Scanner(new File("gamelevels/adventure_mode_levels/list.txt"))) {
			while(scanner.hasNext()) {
				String tmp = scanner.nextLine();
				String[] tmpSplit = tmp.split(",");
				if (tmpSplit[1].equals("1")) {
					modeOneLevels.add(tmpSplit[0]);
					modeOneLevelsState.add(1);
				}
				else if (tmpSplit[1].equals("0")) {
					modeOneLevels.add(tmpSplit[0]);
					modeOneLevelsState.add(0);
				}
			}
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		try (PrintWriter printWriter = new PrintWriter("gamelevels/adventure_mode_levels/list.txt")) {
			int index = modeOneLevels.indexOf(levelName);
			if (index < modeOneLevels.size() - 1)
				modeOneLevelsState.set(index + 1, 1);
			for (int i = 0; i < modeOneLevels.size(); i++) {
				printWriter.println(modeOneLevels.get(i) + "," + modeOneLevelsState.get(i));
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	public  class ActionHandler implements EventHandler<KeyEvent> {
		Hero hero;
		Scene scene;
		
		public ActionHandler(Hero hero, Scene scene) {
			this.hero = hero;
			this.scene = scene;
		}
		

		@Override
		public void handle(KeyEvent e) {
			if (e.getCode()==KeyCode.UP || e.getCode()==KeyCode.W) {
				hero.setRotate(2);
				if (designMap[hero.location.get(0) - 1][hero.location.get(1)] != -1) {
					hero.walkOnGrassAudioClip.play();
					hero.setLocation(hero.location.get(0) - 1, hero.location.get(1));	
					hero.judgeOut(scene);
				}
				else if(designMap[hero.location.get(0) - 1][hero.location.get(1)] == -1) {
					hero.hitAudio.play();
				}
			}
			else if (e.getCode()==KeyCode.DOWN || e.getCode()==KeyCode.S) {
				hero.setRotate(0);
				if (designMap[hero.location.get(0) + 1][hero.location.get(1)] != -1) {
					hero.walkOnGrassAudioClip.play();
					hero.setLocation(hero.location.get(0) + 1, hero.location.get(1));	
					hero.judgeOut(scene);
					
				}
				else if(designMap[hero.location.get(0) + 1][hero.location.get(1)] == -1) {
					hero.hitAudio.play();
				}
			
			}
			else if (e.getCode()==KeyCode.LEFT || e.getCode()==KeyCode.A) {
				hero.setRotate(1);
				if (designMap[hero.location.get(0)][hero.location.get(1) - 1] != -1) {
					hero.walkOnGrassAudioClip.play();
					hero.setLocation(hero.location.get(0), hero.location.get(1) - 1);
					hero.judgeOut(scene);
				}
				else if(designMap[hero.location.get(0)][hero.location.get(1) - 1] == -1) {
					hero.hitAudio.play();
				}
			}
			else if (e.getCode()==KeyCode.RIGHT || e.getCode()==KeyCode.D ) {
				hero.setRotate(3);
				if (designMap[hero.location.get(0)][hero.location.get(1) + 1] != -1) {
					hero.walkOnGrassAudioClip.play();
					hero.setLocation(hero.location.get(0) , hero.location.get(1)+ 1);
					hero.judgeOut(scene);
				}
				else if(designMap[hero.location.get(0)][hero.location.get(1) + 1] == -1) {
					hero.hitAudio.play();
				}
			}
			else if (e.getCode() == KeyCode.Q) {
				if (blockSize.getValue() + 1 < maxBlockSize) {
					isChange = true;
				blockSize.setValue(blockSize.getValue() + 1);
				hero.imageViewSize = hero.imageViewSize + 1;
				}
			}
			else if (e.getCode() == KeyCode.E) {
				if (blockSize.getValue() > 2) {
				isChange = true;
				blockSize.setValue(blockSize.getValue() - 1);
				hero.imageViewSize = hero.imageViewSize - 1;
				}	
			}
		}
	}
}






